﻿#region Imports
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using CommonUtilities.Attributes;
using CommonUtilities.Extensions;
#endregion

namespace DirectoryAnalyzer.Models
{
    [Serializable]
    public class DInfo
    {
        #region Declarations
        private long byteSize;
        #endregion Declarations

        #region Constructors
        public DInfo()
        {
            ;
        }

        public DInfo(string dirPath, long size, long sort, long fileCount)
        {
            Sort = sort;
            DirName = DirPath = RelPath = dirPath;
            FileCount = fileCount;
            ByteSize = size;
            LastModified = "--";
        }

        public DInfo(string dirPath, int sort)
        {
            PopulateProperties(new DirectoryInfo(dirPath), sort);
        }

        public DInfo(DirectoryInfo dirInfo, int sort)
        {
            PopulateProperties(dirInfo, sort);
        }
        #endregion Constructors

        #region Properties
        [Unique]
        [Sortable]
        [DisplayName("Dir. name")]
        public string DirName { get; private set; }

        [Browsable(false)]
        [DisplayName("Full path")]
        public string DirPath { get; private set; }

        [Browsable(false)]
        [DisplayName("Relative path")]
        public string RelPath { get; private set; }

        [Sortable]
        [DisplayName("Size (bytes)")]
        public long ByteSize { get { return byteSize; } private set { byteSize = value; } }

        [DisplayName("Directory size")]
        public string DirSize { get { return ByteSize.ToPracticalSize(); } }

        [Browsable(false)]
        public long Sort { get; set; }

        [Sortable]
        [DisplayName("# files")]
        public long FileCount { get; private set; }

        [Browsable(false)]
        [DisplayName("Avg. size (bytes)")]
        public long AvgByteSize { get { return FileCount == 0 ? 0 : ByteSize / FileCount; } }

        [DisplayName("Avg. size per file (B)")]
        public string AvgFileSize { get { return AvgByteSize.ToPracticalSize(); } }

        [DisplayName("Last modified")]
        public string LastModified { get; private set; }
        #endregion Properties

        #region Methods
        private void PopulateProperties(DirectoryInfo dirInfo, int sort)
        {
            Sort = sort;
            DirName = dirInfo.Name;
            DirPath = dirInfo.FullName;
            RelPath = ".." + Path.DirectorySeparatorChar
                + dirInfo.FullName.Replace(dirInfo.Parent.FullName, "").Trim(Path.DirectorySeparatorChar);
            FileCount = CalculateDirectorySize(DirPath, out byteSize);
            LastModified = dirInfo.LastWriteTime.ToString("yyyy-MMM-dd HH:mm:ss");
        }

        public static long CalculateDirectorySize(string sDirectoryPath, out long dirSize)
        {
            var allFilePaths = Directory.GetFiles(sDirectoryPath, "*.*", SearchOption.AllDirectories).ToObservableCollection();
            if (allFilePaths.GetCount() > 0)
            {
                var allFiles = new ObservableCollection<FileInfo>();
                allFilePaths.ToList().ForEach(file => allFiles.Add(new FileInfo(file)));

                dirSize = allFiles.Select(file => file.GetLength()).Sum();
            }
            else dirSize = 0;

            return allFilePaths.GetCount();
        }

        public override string ToString()
        {
            return String.Format("{0} | {1} / {2} = {3}", this.RelPath, this.DirSize, this.FileCount, this.AvgFileSize);
        }
        #endregion Methods
    }
}
